/*
 * Copyright (c) 2010, Johan T. Larsson All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Mercenary Commander project nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *      
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL JOHAN T. LARSSON BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package games.TBSGame;
import java.io.ObjectOutputStream;
import java.util.Timer;
import java.util.TimerTask;

import games.TBSGame.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Point;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ZoomControls;


public class Game extends Activity implements OnClickListener, GameEnder {
	
	private BattleSurfaceView BattleUI;
	private BattleWorld World;
	private ResourceManager ResourceManager;
	
	private String TurnButtonTag = "TurnButton";
	private String ModeButtonTag = "ModeButton";
	
	private static final int MENU_UNIT_INFO = 0;
	private static final int MENU_SETTINGS = 1;
	private static final int MENU_HELP = 2;
	
	public final static int GAME_START = 1;
	public final static int GAME_OVER = 2;
	public final static int GAME_RUNNING = 2;
	
	public int LocalTeam = 0;
	
	private ProgressDialog ProgDialog;
	
	private Handler MainHandler;
	private Handler OpponentHandler;
	
	private boolean TurnInProgress = false;
	private int TickDelay = 100;
	private int CurrentTick = 0;
	private final int TickAmount = 12;
	private Handler TaskHandler = new Handler();
	
	private Runnable TickTask = new Runnable() {
		public synchronized void run() {
	    	CurrentTick++;
	    	
	    	World.DoTick(1);
	    	synchronized(BattleUI)
			{
				BattleUI.requestRender();
			}
	    	
	    	if(CurrentTick >= TickAmount)
	    	{
	    		TaskHandler.removeCallbacks(TickTask);
	    		World.FinalizeTurn();
	    		SendTurnDone();
	    		
				synchronized(BattleUI)
				{
					BattleUI.requestRender();
				}
				CurrentTick = 0;
	    		SetTurnInProgress(false);
	    	}
	    	else
	    	{
	    		TaskHandler.postDelayed(TickTask, TickDelay);
	    	}
		}
	};
	
	private Runnable LoadingTask = new Runnable() {
		public synchronized void run() {
			synchronized(BattleUI.Renderer)
			{
				if(BattleUI.Renderer.Initialized)
				{
            		ProgDialog.hide();
            	}
				else
				{
					TaskHandler.postDelayed(LoadingTask, 100);
				}
			}
		}
	};

    @Override
    public void onCreate(Bundle state) {
        super.onCreate(state);
       
        ShowLoadingLevelDialog();
        
        ResourceManager = new ResourceManager(this);
        
        if(state == null) {
        	Intent gameState = getIntent();
        	state = gameState.getBundleExtra("GAME_BUNDLE");
        }
        
        boolean needRestore = false;
        if(state.getInt("GAME_STATE") == GAME_START) {
        	World = new BattleWorld(this, state.getString("GAME_LEVEL_XML"), LocalTeam);
        }
        else {
        	World = new BattleWorld(this, 1, LocalTeam);
        	needRestore = true;
        }
        
        setContentView(R.layout.battleview);
        BattleUI = (BattleSurfaceView)findViewById(R.id.battlesurfaceview);
        BattleUI.Initialize(World);
        
        Button turnButton = (Button)findViewById(R.id.EndTurnButton);
        turnButton.setOnClickListener(this);
        
        ImageButton modeButton = (ImageButton)findViewById(R.id.ModeButton);
        modeButton.setOnClickListener(this);
        
        ZoomControls zoomer = (ZoomControls)findViewById(R.id.ZoomControls);
        
        zoomer.setOnZoomInClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            	synchronized(BattleUI.Renderer)
    			{
    				BattleUI.Renderer.Zoom(1.25f);    				
    				BattleUI.requestRender();
    			}
            }});
        zoomer.setOnZoomOutClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            	synchronized(BattleUI.Renderer)
    			{
    				BattleUI.Renderer.Zoom(0.8f);    				
    				BattleUI.requestRender();
    			}
            }});
        
        if(needRestore)
        	RestoreState(state);
        
        MainHandler = new Handler() {
        	@Override
            public void handleMessage(Message msg) {
        		HandleMessage(msg);
            }
        };
        
        if(state.getBoolean("GAME_MULTIPLAYER") == false) {
        	OpponentAI opponent = new OpponentAI();
        	OpponentHandler = opponent.Initialize(MainHandler, World);
        	OpponentHandler.sendEmptyMessage(OpponentAI.MSG_START_GAME);
        }
//        else {
//        	OpponentHandler.sendEmptyMessage(OpponentAI.MSG_START_GAME);
//        	OpponentRemote opponent = new OpponentRemote();
//        	OpponentHandler = opponent.Initialize(MainHandler, World);
//        	if (state.getBoolean("GAME_HOST")) {
//        		opponent.SetupHost(state.getInt("GAME_PORT"));
//        	}
//        	else {
//        		opponent.SetupClient(state.getString("GAME_IP"), state.getInt("GAME_PORT"));
//        	}
//        }
    }
    
    private void HandleMessage(Message msg)
    {
    	switch(msg.what)
    	{
    	case OpponentAI.MSG_RESULT_DONE:
    		World.UnpackageUnits(msg.getData());
    		break;
    	}
    }
    
    public void EndGame(int winner, int optionalGoals)
    {
    	Intent result = new Intent();
    	
    	Bundle state = new Bundle();
    	state.putInt("GAME_STATE", GAME_OVER);
    	state.putInt("GAME_WINNER", winner);
    	state.putInt("GAME_OPTIONAL_GOALS", optionalGoals);

    	result.putExtra("GAME_BUNDLE", state);
    	setResult(RESULT_OK, result);
    	
    	finish();
    }
    
    private void GetPreferences() {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
        TickDelay = Integer.parseInt(prefs.getString("PREF_TICK_DELAY", "0"));
    }
    
    public void ShowLoadingLevelDialog()
    {
    	ProgDialog = ProgressDialog.show(this, "Loading" , "Please wait...", true);
    	TaskHandler.postDelayed(LoadingTask, 100);
    }
    
    public boolean onCreateOptionsMenu(Menu menu)
    {
    	menu.add(0, MENU_UNIT_INFO, 0, "Selection info");
    	menu.add(0, MENU_SETTINGS, 0, "Settings");
    	menu.add(0, MENU_HELP, 0, "Help");
    	return true;
    }
    
    public boolean onOptionsItemSelected(MenuItem item)
    {
    	if(TurnInProgress)
    		return false;
    	switch(item.getItemId()) {
    	case MENU_UNIT_INFO:
    		ShowUnitInfo();
    		return true;
    	case MENU_SETTINGS:
    		ShowOptions();
    		return true;
    	case MENU_HELP:
    		ShowHelp();
    		return true;
    	}
    	return false;
    }
    
    public void ShowOptions()
    {
    	Intent optionIntent = new Intent(this, OptionMenu.class);
        startActivity(optionIntent);	
    }
    
    public void ShowHelp()
    {
    	Intent intent = new Intent(this, HelpHolder.class);
        startActivity(intent);	
    }
    
    // TODO: Very ad hoc. Works for now; shows something that looks acceptable
    public void ShowUnitInfo()
    {
    	Unit unit;
    	Tile tile;
    	synchronized(BattleUI.Renderer)
    	{
    		Point p = BattleUI.Renderer.SelectedTile;
    		if(p == null)
    			return;
    		tile = World.Landscape[p.x][p.y];
    		unit = tile.Unit;
    	}
		
	    AlertDialog.Builder builder = new AlertDialog.Builder(this);
	    builder.setCancelable(true);
	    if(unit != null)
	    {
		    builder.setTitle(unit.Designation);
		    builder.setMessage("Speed:  " + 12/unit.Slowness +
		    		"\nAttack range:  " + unit.Range +
		    		"\nAttack strength:  " + unit.Attack +
		    		"\nDefense strength:  " + unit.Defense + 
		    		"\nDefense bonus: " + tile.DefenseBonus);
	    }
	    else
	    {
	    	builder.setTitle("Empty tile");
	    	if(tile.Passable)
	    		builder.setMessage("Defense bonus: " + tile.DefenseBonus);
	    	else
	    		builder.setMessage("Impassable terrain");
	    }
	    builder.setInverseBackgroundForced(true);
	    builder.setNeutralButton("Done", new DialogInterface.OnClickListener() {
	      @Override
	      public void onClick(DialogInterface dialog, int which) {
	        dialog.dismiss();
	      }
	    });

	    AlertDialog alert = builder.create();
	    alert.show();
    }
    
    
    private void RestoreState(Bundle state) {
    	World.RestoreState(state);
    	BattleUI.RestoreState(state);
    	SetModeImage(BattleUI.MoveMode);
	}
    
	@Override
    protected void onResume() {
    	super.onResume();
    	if(BattleUI != null)
    		BattleUI.onResume();
        
    }

    @Override
	public void onLowMemory() {
    	super.onResume();
    }
    
    @Override
    protected void onPause() {
    	FinalizePendingTurn();
    	super.onPause();
    	if(BattleUI != null)
    		BattleUI.onPause();
    }
    
    @Override
    protected void onStart() {
    	super.onStart();
        GetPreferences();
    }
    
    @Override
    protected void onStop() {
    	FinalizePendingTurn();
    	super.onStop();
    }
    
    @Override
	public synchronized void onBackPressed() {
    	FinalizePendingTurn();
    	
    	Bundle state = new Bundle();
    	
    	if(World != null)
    		World.SaveState(state);
    	
    	state.putInt("GAME_STATE", GAME_RUNNING);
    	
    	Intent result = new Intent();
    	result.putExtra("GAME_BUNDLE", state);
    	setResult(RESULT_OK, result);
    	
    	finish();
    }
    
    @Override
    protected void onDestroy() {
    	FinalizePendingTurn();
    	super.onDestroy();
    }
    
    @Override
    protected synchronized void onSaveInstanceState(Bundle state)
    {
    	FinalizePendingTurn();
    	super.onSaveInstanceState(state);
    	if(World != null)
    		World.SaveState(state);
    	if(BattleUI != null)
    		BattleUI.SaveState(state);
    }
    
    private void FinalizePendingTurn()
    {
    	if(!TurnInProgress)
    		return;
    	
    	TaskHandler.removeCallbacks(TickTask);
		World.DoTick(TickAmount - CurrentTick);
		World.FinalizeTurn();
		SendTurnDone();
    	
		CurrentTick = 0;
    	SetTurnInProgress(false);
    }
    
    private void SendTurnDone()
    {
		Message msg = new Message();
		msg.what = OpponentAI.MSG_START_TURN;
		Bundle msgBundle = new Bundle();
		World.SaveUnitState(msgBundle, World.Units);
		msg.setData(msgBundle);
		OpponentHandler.sendMessage(msg);
    }
    
    private void SetTurnInProgress(boolean value)
    {
    	TurnInProgress = value;
    	synchronized(BattleUI)
    	{
    		BattleUI.Renderer.TurnInProgress = value;
    	}
    }
    
	@Override
	public void onClick(View button) {
		String tag = (String) button.getTag();
		if(tag.equals(TurnButtonTag) && !TurnInProgress)
		{
			if(TickDelay == 0)
			{
				World.DoTick(TickAmount);
				World.FinalizeTurn();
				SendTurnDone();
				synchronized(BattleUI)
				{
					BattleUI.requestRender();
				}
			}
			else
			{
				SetTurnInProgress(true);
				TaskHandler.postDelayed(TickTask, TickDelay);
			}
		}
		else if(tag.equals(ModeButtonTag))
		{
			int mode;
			synchronized(BattleUI){
				mode = BattleUI.SwitchMoveMode();
			}
			SetModeImage(mode);
		}
	}

	private void SetModeImage(int mode) {
		ImageButton modeButton = (ImageButton) findViewById(R.id.ModeButton);
		switch(mode) 
		{
		case 0:
			modeButton.setImageResource(R.drawable.move_mode);
			break;
		case 1:
			modeButton.setImageResource(R.drawable.bombard_mode);
			break;
		}
	}
}
